#include "thread_pool.h"

extern MYSQL* conn;
extern char* rootfile;

void getsCommand(task_t* task){
    //获得filename
    char filename[128] = {0};
    strcpy(filename, task->data);
    printf("filename: %s\n", filename);

    //获得userid
    int userid = -1;
    getUserid(task->peerfd, &userid);
    printf("userid: %d\n", userid);

    //查询当前的pwdid
    int pwdid = -1;
    char query[512] = {0};
    sprintf(query,
            "SELECT pwdid FROM t_user WHERE userid=%d",
            userid);
    mysql_query(conn, query);
    MYSQL_RES* res = mysql_store_result(conn);
    MYSQL_ROW row = mysql_fetch_row(res);
    pwdid = atoi(row[0]);
    mysql_free_result(res);
    printf("pwdid: %d\n", pwdid);

    //查询这个filename对应的fid和md5和filesize
    int fid = -1;
    char md5[33] = {0};
    int filesize = -1;
    memset(query, 0, sizeof(query));
    sprintf(query,
            "SELECT fid,md5,filesize FROM t_file WHERE owner_id=%d AND parent_id=%d AND filename='%s' AND type='f'",
            userid, pwdid, filename);
    mysql_query(conn, query);
    res = mysql_store_result(conn);
    int count = mysql_num_rows(res);
    if(count == 0){     //文件不存在
        mysql_free_result(res);
        fprintf(stderr, "File id not exists.\n");
        sendMsg(task->peerfd, MSG_TYPE_NOT_EXIST, "File is not exists.");;
        return;
    } else {    //文件存在
        row = mysql_fetch_row(res);
        pwdid = atoi(row[0]);
        strcpy(md5, row[1]);
        filesize = atoi(row[2]);
        mysql_free_result(res);
        fid = atoi(row[0]);
        printf("fid: %d\n", fid);
        printf("md5: %s\n", md5);
        printf("filesize: %d\n", filesize);
    }



    int length = 0;
    char path[128] = {0};
    strcat(path, rootfile);
    strcat(path, md5);
    int filefd = open(path, O_RDWR);                 
    if(filefd <= 0){
        sendn(task->peerfd, &length, sizeof(length));
        syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
        return;
    }
    length = filesize;

    int err = sendn(task->peerfd, (char*)&length, sizeof(length));    // 发送文件大小
    if(err==-1){
        close(filefd);
        perror("getsCommand: send file state is failed");
        syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
        return ;
    }

    int offset = 0;
    err = recvn(task->peerfd, (char*)&offset, sizeof(offset));
    if(err==-1){
        close(filefd);
        perror("getsCommand: recv file offset is failed");
        syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
        return ;
    }


    int donesize = 0;

    if(length>200*1024*1024){
        void*p = mmap(NULL, length, 
                      PROT_READ|PROT_WRITE, MAP_SHARED, filefd, 0);   // 文件大于100M时，使用mmap。
        if(p==NULL){
            close(filefd);
            fprintf(stderr, "mmap is failed\n");
            syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
            return;
        }
        int ret = sendn(task->peerfd, (char*)p, length);
        if(ret == -1){
            close(filefd);
            perror("sendFile: send file data is failed");
            syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
            return ;
        }
        donesize += length;
        munmap(p, length);
        close(filefd);
    }else{
        //偏移位置，进行断点续传
        err = lseek(filefd, offset, SEEK_SET);
        if(err==-1){
            close(filefd);
            perror("getsCommand: lseek file offset is failed");
            syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
            return ;
        }
        donesize = offset;
        char buff[1000] = {0};
        while(donesize<length){
            int ret = read(filefd, buff, sizeof(buff));
            if(ret == -1){
                close(filefd);
                perror("sendFile: read file data is failed");
                syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
                return ;
            }
            err = sendn(task->peerfd, (char*)&ret, sizeof(ret));
            if(err == -1){
                close(filefd);
                perror("sendFile: send file data is failed");
                syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
                return ;
            }

            err = sendn(task->peerfd, buff, ret);
            if(err == -1){
                close(filefd);
                perror("sendFile: send file data is failed");
                syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
                return ;
            }
            donesize += ret;
            printf("The file is send: %5.2f%%\r", 100.00*donesize/length);
            fflush(stdout);
        }
        printf("\n");
        close(filefd);
    }
    if(donesize == length){
        fprintf(stderr, "The file %s send successful\n", task->data);
        syslog(LOG_INFO, "User %d gets file %d successfully.", userid, fid);
    }
    else{
        fprintf(stderr, "The file %s send failed\n", task->data);
        syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
    }
}



//2期实现
void getsCommand1(task_t* task){
    int length = 0;
    int filefd = open(task->data, O_RDWR);                 
    if(filefd <= 0){
        sendn(task->peerfd, &length, sizeof(length));
        syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
        return;
    }

    struct stat state;
    int err = fstat(filefd, &state);
    if(err == -1){
        close(filefd);
        perror("getsCommand: get file state is failed");
        syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
        return ;
    }
    length = state.st_size;
    err = sendn(task->peerfd, (char*)&length, sizeof(length));    // 发送文件大小
    if(err==-1){
        close(filefd);
        perror("getsCommand: send file state is failed");
        syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
        return ;
    }

    int offset = 0;
    err = recvn(task->peerfd, (char*)&offset, sizeof(offset));
    if(err==-1){
        close(filefd);
        perror("getsCommand: recv file offset is failed");
        syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
        return ;
    }


    int donesize = 0;

    if(length>200*1024*1024){
        void*p = mmap(NULL, length, 
                      PROT_READ|PROT_WRITE, MAP_SHARED, filefd, 0);   // 文件大于100M时，使用mmap。
        if(p==NULL){
            close(filefd);
            fprintf(stderr, "mmap is failed\n");
            syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
            return;
        }
        int ret = sendn(task->peerfd, (char*)p, length);
        if(ret == -1){
            close(filefd);
            perror("sendFile: send file data is failed");
            syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
            return ;
        }
        donesize += length;
        munmap(p, length);
        close(filefd);
    }else{
        //偏移位置，进行断点续传
        err = lseek(filefd, offset, SEEK_SET);
        if(err==-1){
            close(filefd);
            perror("getsCommand: lseek file offset is failed");
            syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
            return ;
        }
        donesize = offset;
        char buff[1000] = {0};
        while(donesize<length){
            int ret = read(filefd, buff, sizeof(buff));
            if(ret == -1){
                close(filefd);
                perror("sendFile: read file data is failed");
                syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
                return ;
            }
            err = sendn(task->peerfd, (char*)&ret, sizeof(ret));
            if(err == -1){
                close(filefd);
                perror("sendFile: send file data is failed");
                syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
                return ;
            }

            err = sendn(task->peerfd, buff, ret);
            if(err == -1){
                close(filefd);
                perror("sendFile: send file data is failed");
                syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
                return ;
            }
            donesize += ret;
            printf("The file is send: %5.2f%%\r", 100.00*donesize/length);
            fflush(stdout);
        }
        printf("\n");
        close(filefd);
    }
    if(donesize == length){
        fprintf(stderr, "The file %s send successful\n", task->data);
        syslog(LOG_INFO, "User execute GETSFILE command: SUCCESSFUL.");
    }
    else{
        fprintf(stderr, "The file %s send failed\n", task->data);
        syslog(LOG_ERR, "User execute GETSFILE command: FAILED.");
    }
}
